/*
 * Copyright 2008 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.splink.asbeangen.parser.iface;

import java.util.ArrayList;
import java.util.List;

import org.splink.asbeangen.templates.IClassTemplate;
import org.splink.asbeangen.templates.ITemplateClass;
import org.splink.asbeangen.templates.IWritableClass;
import org.splink.asbeangen.templates.as3.AS3Interface;

public class InterfaceBuilder {
	public static String NEW_LINE = System.getProperty("line.separator");

	private List<Interfaze> _ifazes;
	private List<ITemplateClass> _clazzStack;
	private List<IWritableClass> _interfaceStack;
	private IClassTemplate _template;
	private String _packagename;
	private List<String> _copyright;

	public InterfaceBuilder(List<String> copyright, String packagename, List<Interfaze> ifazes,
			List<ITemplateClass> clazzStack, IClassTemplate template) {
		_packagename = packagename;
		_ifazes = ifazes;
		_clazzStack = clazzStack;
		_interfaceStack = new ArrayList<IWritableClass>();
		_template = template;
		_copyright = copyright;

		build();
	}

	private void build() {
		for (Interfaze ifaze : _ifazes) {
			String[] implementors = ifaze.getImplementors();
			_interfaceStack.add(createInterfaze(ifaze.getName(), implementors));
		}
	}

	private IWritableClass createInterfaze(String name, String[] implementors) {
		String imports = "";
		String methods = "";

		// creates an interface with the methods which are implemented
		// in all interface implementors
		List<String> list = new ArrayList<String>();
		for (String str : implementors) {
			ITemplateClass clazz = getClazzByName(str);

			imports += clazz.getImports().trim();
			String convertedFnc = convertMethods(clazz.getMethods());
			String[] convertedFncLines = convertedFnc.split(NEW_LINE);
			for (String fncLine : convertedFncLines) {
				fncLine = fncLine.trim();
				if (!fncLine.equals("")) {
					if (list.contains(fncLine) || implementors.length < 2) {
						if(methods.indexOf(fncLine) == -1) {
							methods += "		" + fncLine + ";\r\n\r\n";
						}
					}
					
					if(!list.contains(fncLine)) {
						list.add(fncLine);
					}
				}
			}

			// only import classes which are defined within the interface
			String[] i = imports.split(NEW_LINE);
			imports = "";
			for (String imp : i) {
				String completeImport = imp;
				if (imp.equals(""))
					continue;
				imp = imp.split(" ")[1];
				imp = imp.replace(";", "");
				if (imp.indexOf(".") != -1) {
					String[] simp = imp.split("\\.");
					imp = simp[simp.length - 1];
				}

				if (methods.contains(imp)) {
					imports += completeImport;
				}
			}

		}

		String str = _template.getComment(_copyright) + "package " + _packagename + "\r\n" + "{\r\n" + " " + imports
				+ "\r\n" + "	public interface " + name + "\r\n" + "	{\r\n" + methods + "	}\r\n" + "}\r\n";

		return new AS3Interface(name, str, _packagename);
	}

	/**
	 * Convert class methods to interface methods and strip public, comments and method bodies
	 */
	private String convertMethods(String methods) {
		methods = methods.replaceAll("public", "");
		methods = methods.replaceAll("\\{[^}]*\\}", "");
		methods = methods.replaceAll("\\}[^}]*\\}", "");
		methods = methods.replaceAll("\\/\\*[^/]*\\/", "");
		return methods;
	}

	private ITemplateClass getClazzByName(String name) {
		for (ITemplateClass clazz : _clazzStack) {
			if (name.equals(clazz.getID())) {
				return clazz;
			}
		}
		return null;
	}

	public List<IWritableClass> getInterfaceStack() {
		return _interfaceStack;
	}
}
